﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO.Ports;
using System.Windows.Forms;
using System.Drawing;
using System.Threading;
using System.Collections;
using System.Runtime.InteropServices;

namespace PowerView.Page
{
    public static class MiddleWare
    {
        public static Color default_color = Color.Red;
        public static SerialPort serial_port = null;
        public static TextBox log_tBox = null;
        public static ComboBox com_cBox = null;
        
        public static Queue CMD_Queue = new Queue();
        public static Queue Wave_Queue = new Queue();


        static byte[] write_buff = new byte[256];
        static byte[] read_buff  = new byte[2048];
        static int remain_data_len = 0;

        public const int Wave_Buff_Len  = 8192;
        public static int Wave_Buff_Index = 0;
        public static byte[,] wave_buff = new byte[Wave_Buff_Len, 128]; // 用于存放波形数据

        static IntPtr read_buff_Ptr = Marshal.UnsafeAddrOfPinnedArrayElement(read_buff, 0);

        public static Thread recv_thread = new Thread(DataReceived_Thread);

        private static byte CRC_8_POLYNOMIAL = 0x5E;
        private static byte CRC8_Calculate(byte[] pData,int Size)
        {
            int i, j = 0;
            byte rCRC = 0;
            while (Size-- > 0)
            {
                rCRC ^= pData[j++];
                for (i = 8; i > 0; --i)
                {
                    if ((rCRC & 0x80) != 0) rCRC = (byte)((rCRC << 1) ^ CRC_8_POLYNOMIAL);
                    else rCRC = (byte)(rCRC << 1);
                }
            }
            return (rCRC);
        }

        public static string ByteArrayToString(byte[] arrInput, int len)
        {
            int i;
            StringBuilder sOutput = new StringBuilder(len * 2);
            for (i = 0; i < len; i++)
            {
                sOutput.Append(arrInput[i].ToString("X2"));
                sOutput.Append(arrInput[i].ToString(" "));
            }
            //将此实例的值转换为System.String
            return sOutput.ToString();
        }

        public static byte[] HexStringToByteArray(string str)
        {
            str = str.Replace(" ", "");
            byte[] buffer = new byte[(str.Length) / 2];

            if((str.Length < 2) || (str.Length % 2 != 0))
            {
                return buffer;
            }
            for (int i = 0; i < str.Length; i += 2)
                buffer[i / 2] = (byte)Convert.ToByte(str.Substring(i, 2), 16);
            return buffer;
        }
        static public byte CRC8_Calculate(byte[] pData, int Size, byte CRC_8_POLYNOMIAL)
        {
            byte i, p = 0;
            byte rCRC = 0;
            while (Size-- > 0)
            {
                rCRC ^= pData[p++];
                for (i = 8; i > 0; --i)
                {
                    if ((rCRC & 0x80) > 0) rCRC = (byte)((rCRC << 1) ^ CRC_8_POLYNOMIAL);
                    else rCRC = (byte)(rCRC << 1);
                }
            }
            return (rCRC);
        }

        static void DataReceived_Thread()
        {
            while (true)
            {
                if (serial_port == null || serial_port.IsOpen == false)
                {
                    Thread.Sleep(100);
                    continue;
                }
                try
                {
                    int length = serial_port.BytesToRead;

                    if (length < 7)
                    {
                        Thread.Sleep(30);
                        continue;
                    }
                    serial_port.Read(read_buff, remain_data_len, length);
                    remain_data_len += length;
                    while (true)
                    {
                        if (read_buff[0] != 0x55)
                        {
                            remain_data_len = 0;
                            break;
                        }

                        if (remain_data_len < read_buff[5] + 7)
                        {
                            break;
                        }

                        remain_data_len -= (read_buff[5] + 7);

                        if (read_buff[2] == 0x01) // wave data
                        {
                            Buffer.BlockCopy(read_buff, 6, wave_buff, Wave_Buff_Index * 128, read_buff[5]);
                            Wave_Buff_Index++;
                            if (Wave_Buff_Index == Wave_Buff_Len)
                            {
                                Wave_Buff_Index = 0;
                            }
                            //Console.WriteLine(ByteArrayToString(read_buff, 23));
                        }
                        else
                        {
                            byte[] cmd = new byte[read_buff[5] + 7];
                            Buffer.BlockCopy(read_buff, 0, cmd, 0, read_buff[5] + 7);
                            CMD_Queue.Enqueue(cmd);
                            log_tBox.AppendText("Rx:" + ByteArrayToString(read_buff, read_buff[5] + 7) + "\r\n");
                        }
                        if (remain_data_len > 0)
                        {
                            read_buff_Ptr = Marshal.UnsafeAddrOfPinnedArrayElement(read_buff, read_buff[5] + 7);
                            Marshal.Copy(read_buff_Ptr, read_buff, 0, remain_data_len);
                        }
                    }
                }
                catch (Exception)
                {
                }
            }
        }

        public static int Write_CMD(byte ch, byte Protocol, UInt16 CMD, byte[] data, byte len)
        {
            if (serial_port == null || serial_port.IsOpen == false)
            {
                com_cBox.BackColor = Color.Pink;
                log_tBox.AppendText("请先打开串口!!\r\n");
                return -1;
            }
            write_buff[0] = 0x55;
            write_buff[1] = ch;
            write_buff[2] = (byte)(Protocol | (byte)(CMD >> 8));
            write_buff[3] = (byte)(CMD & 0xFF);
            write_buff[4] = 0x00;
            write_buff[5] = len;

            for (int i = 0; i < len; i ++)
            {
                write_buff[6 + i] = data[i];
            }

            write_buff[6 + len] = CRC8_Calculate(write_buff, 6 + len); //CRC
            len += 7;
            try
            {
                serial_port.Write(write_buff, 0, len);
                log_tBox.AppendText("Tx:" + ByteArrayToString(write_buff, len) + "\r\n");
            }
            catch (Exception)
            {
                com_cBox.BackColor = Color.Pink;
                log_tBox.AppendText("数据发送失败!!\r\n");
                return -2;
            }
            return 0;
        }
    }
}
